from typing import *


class Matrix:
    # <editor-fold desc="Overwrite">
    def __init__(self, size: int, initialValue=0):
        self.__size = size
        self.__iterator = 0  # Pointer of the iterator
        self.__matrix = [[initialValue for i in range(size)] for i in range(size)]

    def __next__(self):
        if self.__iterator < self.size ** 2:
            val = self.__matrix[self.__iterator // self.size][self.__iterator % self.size]
            self.__iterator += 1
            return val
        else:
            raise StopIteration

    def __iter__(self):
        return self

    def __setitem__(self, key: int or tuple or str, value):
        if type(key) == tuple:
            if len(key) == 2:
                if key[0] is None:
                    if not isinstance(value, Iterator):
                        raise TypeError("value must be Iterator!")
                    else:
                        self.__setColumn__(key[1], value)
                else:
                    self.__matrix[key[0]][key[1]] = value
            else:
                raise ValueError("len of key tuple must be 2!")
        elif type(key) == int:
            if key >= self.size:
                raise ValueError("key out of range!")
            elif not isinstance(value, Iterator):
                raise TypeError("value must be Iterator!")
            else:
                self.__setRow__(key, value)
        elif type(key) == str:
            if not isinstance(value, Iterator):
                raise TypeError("value must be Iterator!")
            else:
                if key == "\\":
                    self.__setMainDiagonal__(value)
                elif key == "/":
                    self.__setSubDiagonal__(value)
                else:
                    raise ValueError("invalid value of key!")
        else:
            raise TypeError("invalid type of key!")

    def __getitem__(self, key: int or tuple or str):
        if type(key) == tuple:
            if len(key) == 2:
                if key[0] is None:
                    return self.__getColumn__(key[1])
                else:
                    return self.__matrix[key[0]][key[1]]
            else:
                raise ValueError("len of key tuple must be 2!")
        elif type(key) == int:
            if key >= self.size:
                raise ValueError("key out of range!")
            else:
                return self.__getRow__(key)
        elif type(key) == str:
            if key == "\\":
                return self.__getMainDiagonal__()
            elif key == "/":
                return self.__getSubDiagonal__()
            else:
                raise ValueError("invalid value of key!")
        else:
            raise TypeError("invalid type of key!")
    # </editor-fold>

    # <editor-fold desc="Private">
    def __getRow__(self, index: int):
        return (i for i in self.__matrix[index])

    def __getColumn__(self, index: int):
        return (self.__matrix[i][index] for i in range(self.size))

    def __getMainDiagonal__(self):
        for i in range(self.size):
            yield self.__matrix[i][i]

    def __getSubDiagonal__(self):
        for i in range(self.size):
            yield self.__matrix[i][self.size - i - 1]

    def __setRow__(self, index: int, value: Iterator):
        for i in range(self.size):
            try:
                self.__matrix[index][i] = next(value)
            except StopIteration:
                return

    def __setColumn__(self, index: int, value: Iterator):
        for i in range(self.size):
            try:
                self.__matrix[i][index] = next(value)
            except StopIteration:
                return

    def __setMainDiagonal__(self, iterator: Iterator):
        for i in range(self.size):
            try:
                self.__matrix[i][i] = next(iterator)
            except StopIteration:
                return

    def __setSubDiagonal__(self, iterator: Iterator):
        for i in range(self.size):
            try:
                self.__matrix[i][self.size - i - 1] = next(iterator)
            except StopIteration:
                return
    # </editor-fold>

    # <editor-fold desc="Public">
    @property
    def size(self):
        return self.__size

    def transpose(self):
        for i in range(0, self.size):
            for j in range(i + 1, self.size):
                self.__matrix[i][j], self.__matrix[j][i] = self.__matrix[j][i], self.__matrix[i][j]

    def print(self):
        for row in self.__matrix:
            print(row)
    # </editor-fold>
